package com.huijie.app.u.shiro.impl;

import com.google.common.collect.Lists;
import com.huijie.app.u.mapper.RoleResourceMapper;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.util.AntPathMatcher;
import org.apache.shiro.util.PatternMatcher;
import org.jsets.shiro.model.CustomRule;
import org.jsets.shiro.model.RolePermRule;
import org.jsets.shiro.service.ShiroFilteRulesProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
* @ClassName: FilteRulesProviderImpl
* @Description: 动态过滤规则提供者实现
* @author Alex
* @date 2018年6月29日 下午5:36:42
*/
@Service
public class FilteRulesProviderImpl implements ShiroFilteRulesProvider {
	
	@Autowired
	private RoleResourceMapper roleResourceMapper;

	private static RequestMappingHandlerMapping handlerMapping;

	private static List<String> getJwtWhiteList(){
	    String urls="/cms/resource/part-resource";
		List<String> res = new ArrayList<>(8);
	    if(StringUtils.isNotBlank(urls)){
			for (String url : urls.split(";")) {
				if (StringUtils.isNotBlank(url)) {
					res.add(url);
				}
			}
        }
        return res;
    }

	public static RequestMappingHandlerMapping getHandlerMapping() {
		return handlerMapping;
	}

	public static void setHandlerMapping(RequestMappingHandlerMapping handlerMapping) {
		FilteRulesProviderImpl.handlerMapping = handlerMapping;
	}

	/**
	 * 加载基于角色/资源的过滤规则
	 * <br>大部分系统的安全体系都是RBAC(基于角色的权限访问控制)授权模型。
	 * <br>即：用户--角色--资源(URL),对应关系可配并且存储在数据库中。
	 * <br>此方法提供的数据为：RolePermRule{url资源地址、needRoles需要的角色列表}
	 * <br>在shiro中生成的过滤器链为：url=roles[角色1、角色2、角色n]
	 * <br>当用户持有[角色1、角色2、角色n]中的任何一个角色，则给予访问，否则不予访问
	 * 
	 * <br>权限指用户能操作资源的统称、角色则说权限的集合。
	 * <br>权限授权模型直接表示为：用户--资源(URL)。
	 * <br>此方法提供的数据格为：PermRule{url资源地址、needPerms需要的权限列表}
	 * <br>在shiro中生成的过滤器链为：url=perms[权限编码1、权限编码2、权限编码n]
	 * <br>当用户持有[权限编码1、权限编码2、权限编码n]中的任何一个权限，则给予访问，否则不予访问
	 * 
	 * @return  @see org.jsets.shiro.model.RolePermRule
	 *
	 */
	@Override
	public List<RolePermRule> loadRolePermRules(){
		//默认过滤规则清空
		//List<RolePermRule> rolePermRules = roleResourceMapper.selectRoleResourceListAll();
		return null;
	}

	@Override
	public List<RolePermRule> loadHmacRules() {
		/// HMAC数字签名鉴权过滤规则配置
		/// 为了展示数据原貌使用了编码配置
		/// 真实场景中可以通过界面配置，比如做一个"接口管理"功能
		/// 或者放到"资源管理"中和菜单、按钮一块管理
		/// 删除操作需要通过HMAC数字摘要认证并且具有"role_admin"角色
		RolePermRule hmacRule1 = new RolePermRule();
		hmacRule1.setUrl("/hmac_api/delete");
		hmacRule1.setNeedRoles("role_admin");
		/// 其余操作需要通过HMAC数字摘要认证
		RolePermRule hmacRule2 = new RolePermRule();
		hmacRule2.setUrl("/hmac_api/**");
		List<RolePermRule> hmacRules = Lists.newLinkedList();
		hmacRules.add(hmacRule1);
		hmacRules.add(hmacRule2);
		return hmacRules;
	}

	@Override
	public List<RolePermRule> loadJwtRules() {
		/// JWT令牌鉴权过滤规则配置
		/// 为了展示数据原貌使用了编码配置
		/// 真实场景中可以通过界面配置，比如做一个"接口管理"功能
		/// 或者放到"资源管理"中和菜单、按钮一块管理
		
		/// 删除操作需要通过JWT令牌认证并且具有"role_admin"角色
//		RolePermRule jwtRule1 = new RolePermRule();
//		jwtRule1.setUrl("/bus/delete");
//		jwtRule1.setNeedRoles("role_admin");
		/// 其余操作需要通过JWT令牌认证
//		RolePermRule jwtRule2 = new RolePermRule();
//		jwtRule2.setUrl("/bus/master-data/factory");
		/* jwtRule2.setNeedRoles("ssss"); */

//        List<RolePermRule> jwtRules = Lists.newLinkedList();
//        jwtRules.add(jwtRule1);
//        jwtRules.add(jwtRule2);

		//管理员角色ID  TODO 数据字典中配置
        String adminRoleId = "0";
        List<RolePermRule> jwtRules = new ArrayList<>(300);
//		RolePermRule jwtRule1 = new RolePermRule();
//		jwtRule1.setUrl("/bus/**");
//		jwtRule1.setNeedRoles("0,1,2");
//		jwtRules.add(jwtRule1);

		//加载资源表中所有的url配置
		List<RolePermRule> rolePermRules = roleResourceMapper.selectAllResourceRoles();
		rolePermRules.forEach(e->{
			e.setNeedRoles(adminRoleId+","+e.getNeedRoles());
			jwtRules.add(e);
		});

		//若存在WebContext,handlerMapping,先加载mvc中所有的url配置，后置
		if(handlerMapping!=null) {
			Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
			handlerMethods.entrySet().forEach(e -> {
				PatternsRequestCondition patternsCondition = e.getKey().getPatternsCondition();
				RequestMethodsRequestCondition methodsCondition = e.getKey().getMethodsCondition();
				int size = methodsCondition.getMethods().size();
				patternsCondition.getPatterns().forEach(pattern -> {
					RolePermRule rolePermRule = new RolePermRule();
					pattern = pattern.replaceAll("\\{[^}]*\\}","*");
					rolePermRule.setUrl(pattern);
					rolePermRule.setNeedRoles(adminRoleId);
					jwtRules.add(rolePermRule);
//					if (size == 0) {
//						RolePermRule rolePermRule = new RolePermRule();
//						rolePermRule.setUrl(pattern);
//						rolePermRule.setNeedRoles(adminRoleId);
//						jwtRules.add(rolePermRule);
//					} else {
//						methodsCondition.getMethods().forEach(method -> {
//							RolePermRule rolePermRule = new RolePermRule();
//							rolePermRule.setUrl(pattern + "==" + method);
//							rolePermRule.setNeedRoles(adminRoleId);
//							jwtRules.add(rolePermRule);
//						});
//					}
				});
			});
		}

		//比较规则：url属子集放前面，有method放前面，剩余的根据url名称升序
		Comparator<RolePermRule> comparatorRule = new Comparator<RolePermRule>() {
			PatternMatcher antPathMatcher = new AntPathMatcher();
			int i = 0;

			@Override
			public int compare(RolePermRule o1, RolePermRule o2) {
//				System.out.print((++i)+":"+o1.getUrl()+"||||||"+o2.getUrl());
				String[] split1 = o1.getUrl().split("==");
				String[] split2 = o2.getUrl().split("==");
				String url1 = split1[0];
				String method1 = split1.length>1?split1[1]:"";
				String url2 = split2[0];
				String method2 = split2.length>1?split2[1]:"";

				int result = url1.compareTo(url2);
				if(!url1.equals(url2)){
					//url不一致时判断谁包含谁，被包含的就是子集
					if (antPathMatcher.matches(url1, url2)) {
						if(result<0){
							result*=-1;
						}
					}else if(antPathMatcher.matches(url2, url1)){
						if(result>0){
							result*=-1;
						}
					}
				}else if(!method1.equals(method2)){
					//url一样method不一样时，method为空的是父集
					if("".equals(method1)){
						if(result<0){
							result*=-1;
						}
					}else if("".equals(method2)) {
						if (result > 0) {
							result *= -1;
						}
					}
				}
//				System.out.println("|||result:"+result);
				return result;
			}
		};
		jwtRules.sort(comparatorRule);

		//根据常量字典白名单过滤
		List<String> jwtWhiteList = getJwtWhiteList();
		if(jwtWhiteList.size()>0){
			for (String url : jwtWhiteList) {
				RolePermRule rolePermRule = new RolePermRule();
				rolePermRule.setUrl(url);
				rolePermRule.setNeedRoles("");
				jwtRules.add(0,rolePermRule);
			}
		}

		return jwtRules;
	}

	@Override
	public List<CustomRule> loadCustomRules() {
		return null;
	}
	
}